import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;

import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;


public class CopyOfCachedTickCounter extends TickCounter {

	public CopyOfCachedTickCounter() throws NoSuchAlgorithmException, InvalidKeyException,
	NoSuchPaddingException {
		super();
	}

	private AtomicBoolean myLittleMony;
	AtomicReference<byte[]> cachedInput;
	AtomicReference<byte[]> cachedOutput;
	
	private boolean cmpArrs(byte[] a, byte[] b) {
		boolean isEqual = true;
		for (int i = 0; i < a.length; ++i)
			if (a[i] != b[i]) return false;
		return isEqual;
	}
	
	@Override
	public byte[] cipher(byte[] in) throws IllegalBlockSizeException, BadPaddingException {
		{
			byte[] temp;
			byte[] result;
			do {
				temp = cachedInput.get();
				result = cachedOutput.get();
			} while (temp != cachedInput.get());
			if (temp != null && cmpArrs(temp, in)) {
				return result;
			}
		}

		while (!myLittleMony.compareAndSet(false, true)) {
			Thread.yield();
		}
		byte[] out = cipher.doFinal(in);
		if (cachedInput == null || !cmpArrs(cachedInput, in)) {
			cachedInput = Arrays.copyOf(in, in.length);
			cachedOutput = out;
		}
		cachedIn = super.nextKey();
		myLittleMony.set(false);
		return cachedValue;
	}
	
	/*
	Future<V> result == cache.get(ar);
	if (result == null ()) {
		Callable<V> task = new Callable<V>() {
			@Override
			public V call() throws Exception {
				return c.compute(arg);
			}
		};
		FutureTask<V> ft = new FutureTask<V>(task);
		cache.putIfAbsent(arg, ft);
		ft.run();
		result = ft;
	}
	try {
		result.get();
	} catch (ExecutionException e) {
		throw new RuntimeException(e);
	}
	*/
}
